import random
from tree import Tree
from node import Node

class GenerateTree:

    def __init__(self, originalTrees, changedTrees, changes, randomTrees, size):
        self.originalTrees = originalTrees
        self.changedTrees = changedTrees
        self.randomTrees = randomTrees
        self.changes = changes
        self.type = "ordered"
        self.size = size
        self.ordered = ["rotation", "delete", "relabelUnique", "insertUnique"]
        self.unordered = ["rotations", "delete", "relabel", "insert", "switch"]


    def getOrdered(self):
        self.type = "ordered"
        #return self.getTrees()

    def getTrees(self):
        originalTrees = []
        randomTrees = []
        changedTrees = []
        for tree in range(0,self.randomTrees):
            nodes = random.randint(1, self.size)
            randomTrees.append(self.getTreeOrdered(nodes))
        for tree in range(0, self.original):
            nodes = random.randint(1, self.size)
            original = self.getTreeOrdered(nodes)
            originalTrees.append(original)
            for tree in range(0, self.changes):
                change = self.getChangeTree(original)
                changedTrees.append(change)
        return (orginalTrees, randomTrees, changedTrees)

    def getUnordered(self):
        self.type = "unordered"
        return self.getTrees()

    def getTreeOrdered(self, nodes=None, symbols=None):
        if nodes is not None:
            self.size = nodes
        root = Node("root", style=Node.ROOT)
        tree = Tree(root)
        numbers = []
        for number in range(0,self.size):
            check = True
            while check:
                if symbols is None:
                    symbol = str(random.randint(0,1000))
                else:
                    symbol = symbols[random.randint(0,len(symbols)-1)]
                if symbol not in numbers:
                    numbers.append(symbol)
                    tree.addChildRandom(symbol, len(numbers))
                    check = False
                    tree.setSize(self.size+1)
        return tree

    def getTreeUnordered(self, nodes):
        if nodes is not None:
            self.size = nodes
        root = Node("root", Node.ROOT)
        tree = Tree(root)
        numbers = []
        for number in range(0,self.size):
            symbol = str(random.randint(0,1000))
            numbers.append(symbol)
            tree.addChildRandom(symbol, len(numbers))
            tree.setSize(self.size+1)
        return tree

    def getChangedTree(self, tree):
        sizeOrdered = len(self.ordered)-1
        sizeUnordered = len(self.unordered)-1
        for item in range(0,self.changes):
            node = self.getNode(tree)
            #print "Label: %s" % node.getLabel()
            if self.type == "ordered":
                operation = self.ordered[random.randint(0,sizeOrdered)]
                self.getOperations(operation, node, tree)
            elif self.type == "unordered":
                operation = self.unordered[random.randint(0,sizeUnordered)]
                self.getOperations(operation, node, tree)
        return tree

    def getOperations(self, name, node, tree):
        if node is not None:
            #print "Operation: %s" % (name)
            #print "Operation Node: %s" % str(node)
            #print "Root: %s" % (tree.getRoot().getChild1())
            if name == "rotation":
                self.rotateNode(node)
            elif name == "delete":
                self.deleteNode(node)
            elif name == "insert":
                self.insertNode(node)
            elif name == "switch":
                number = random.randint(0, self.size)
                randomNode = self.getNode(number, tree)
                self.switchNodes(node, randomNode)
            elif name == "insertUnique":
                self.insertUniqueNode(node, tree)
            elif name == "relabelUnique":
                label = self.findUnique(tree)
                self.relabelNode(node, label)
            elif name == "relabel":
                label = random.randint(-10000, 10000)
                self.relabelNode(node, label)
            else:
                return

    def getNode(self, tree, number=None):
        if number is None:
            number = random.randint(0, tree.getSize())
        count = 0
        for node in tree.iterator(tree.getRoot()):
            if count == number and node is not None:
                if node.getParent() is not None:
                    #print "Node: %s" % str(node)
                    return node
            count = count + 1
        #print "Root: %s" % str(tree.getRoot().getChild1())
        return tree.getRoot().getChild1()


    def rotateNode(self, node):
        node.rotation()

    def deleteNode(self, node):
        parent = node.getParent()
        child1 = node.getChild1()
        child2 = node.getChild2()
        if parent.getChild1() is not None:
            if node.getID() == parent.getChild1().getID():
                if parent.getStyle() is not "ROOT":
                    parent.setChild1(child1)
                elif child1 is not None:
                    parent.setChild1(child1)
                    child1.setChild2(child2)
        elif parent.getChild2() is not None:
            if node.getID() is parent.getChild2().getID():
                if parent.getStyle() is not "ROOT":
                    parent.setChild2(child1)
                elif child1 is not None:
                    parent.setChild1(child1)
                    child1.setChild2(child2)

    def findUnique(self, tree):
        labels = []
        for item in tree.iterator(tree.getRoot()):
            labels.append(item.getLabel())
        label = ""
        while(True):
            label = str(random.randint(-10000, 10000))
            if label not in labels:
                return label

    def insertUniqueNode(self, location, tree):
        child = random.randint(1,2)
        label = self.findUnique(tree)
        node = Node(label, location, style=Node.NORM)
        if child == 1:
            child1 = location.getChild1()
            location.setChild1(node)
            node.setChild1(child1)
            if child1 is not None:
                child1.setParent(node)
        elif child == 2:
            child2 = location.getChild2()
            location.setChild2(node)
            node.setChild2(child2)
            if child2 is not None:
                child2.setParent(node)

    def insertNode(self, location, node):
        child = random.randint(1,2)
        child1 = location.getChild1()
        child2 = location.getChild2()
        if child == 1:
            location.setChild1(node)
            node.setChild1(child1)
            child1.setParent(node)
        else:
            location.setChild2(node)
            node.setChild2(child2)
            child2.setParent(node)

    def relabelNode(self, node, label):
        node.setLabel(label)

    def switchNodes(self, first, second):
        firstParent = first.getParent()
        firstChild1 = first.getChild1()
        firstChild2 = first.getChild2()
        secondParent = second.getParent()
        secondChild1 = second.getChild1()
        secondChild2 = second.getChild2()
        first.setChild1(secondChild1)
        first.setChild2(secondChild2)
        second.setChild1(firstChild1)
        second.setChild2(firstChild2)
        if first.getID() == firstParent.getChild1().getID():
            if second.getID() == secondParent.getChild1().getID():
                secondParent.setChild1(first)
            else:
                secondParent.setChild2(first)
            firstParent.setChild1(second)
        else:
            if second.getID() == secondParent.getChild1().getID():
                secondParent.setChild1(first)
            else:
                secondParent.setChild2(first)
            firstParent.setChild2(second)
                
                    
                
